﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using netDxf.Entities;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using LightCAD.MathLib;

namespace LightCAD.Drawing.Actions
{
    public class DimRadialAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;

        static DimRadialAction()
        {
            CommandName = "DIMRADIAL";
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "DIMRAD",
                Description = "DIMRADIAL",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="Step0", Options="选择圆或圆弧:" },
                }
            };
            
        }

        internal static void Initilize()
        {
            ElementActions.DimRadial = new DimRadialAction();
            LcDocument.ElementActions.Add(BuiltinElementType.DimRadial, ElementActions.DimRadial);
        }

        private PointInputer inputer { get; set; }

        private Vector2 point;
        private Vector2 center;
        private double raduis;
        public DimRadialAction() { }
        public DimRadialAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令 ：DIMRADIAL");
        }
        private LcCreateMethod GetMethod(string method)
        {
            if (method == null) return CreateMethods[0];
            var getted= CreateMethods.FirstOrDefault((m) => m.Name == method);
            if (getted == null)
                return CreateMethods[0];
            else
                return getted;
        }
        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            //this.Segments = new List<RolineSegment>();
            var curMethod = CreateMethods[0];
            var ElementInputer = new ElementInputer(this.docEditor);
            this.inputer = new PointInputer(this.docEditor);
            Step0:
            var step0 = curMethod.Steps[0];


            var result0 = await ElementInputer.Execute(step0.Options);
            if (ElementInputer.isCancelled) { this.Cancel(); return; }
            // zcb: 增加Res0为空的判定
            if (result0 == null)
            {
                this.Cancel();
                goto End;
            }
            if (result0.ValueX == null)
            {
                goto Step0;
            }
            else
            {
                LcElement element = (LcElement)result0.ValueX;
                this.point = (Vector2)result0.Extent;
                if (CreateSelects(element))
                {
                    //记住圆的圆心点 以及半径
                    if (element is LcCircle || element is LcArc)
                    {
                        if (element is LcCircle)
                        {
                            var circle = element as LcCircle;
                            this.center = circle.Center;
                            this.raduis = circle.Radius;
                            #region
                            LcLine lcline = new LcLine(circle.Center, this.point);
                            //需要移动的向量方向
                            Vector2 direction = new Vector2(0, 0);
                            //需要移动的距离
                            double dis = Math.Abs(lcline.Length - this.raduis);
                            if (lcline.Length > this.raduis)
                            {
                                //向内延伸
                                direction = new Vector2(this.center.X - this.point.X, this.center.Y - this.point.Y);
                            }
                            else if (lcline.Length < this.raduis)
                            {
                                //向外部延伸
                                direction = new Vector2(this.point.X - this.center.X, this.point.Y - this.center.Y);
                            }
                            if (direction.Length() != 0)
                            {
                                //新的移动后的点位
                                Vector2 lidisptpos = this.point + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                                this.point = lidisptpos;
                            }
                            #endregion
                            CreateDimElement();
                            goto End;
                        }
                        else {
                            var circle = element as LcCircle;
                            this.center = circle.Center;
                            this.raduis = circle.Radius;
                            #region
                            LcLine lcline = new LcLine(circle.Center, this.point);
                            //需要移动的向量方向
                            Vector2 direction = new Vector2(0, 0);
                            //需要移动的距离
                            double dis = Math.Abs(lcline.Length - this.raduis);
                            if (lcline.Length > this.raduis)
                            {
                                //向内延伸
                                direction = new Vector2(this.center.X - this.point.X, this.center.Y - this.point.Y);
                            }
                            else if (lcline.Length < this.raduis)
                            {
                                //向外部延伸
                                direction = new Vector2(this.point.X - this.center.X, this.point.Y - this.center.Y);
                            }
                            if (direction.Length() != 0)
                            {
                                //新的移动后的点位
                                Vector2 lidisptpos = this.point + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                                this.point = lidisptpos;
                            }
                            #endregion
                            CreateDimElement();
                            goto End;
                        }
                    }
                }
                else
                {
                    goto Step0;
                }
            }
  
            End:
            this.EndCreating();

        }
        private void CreateDimElement()
        {
            var doc = this.docRt.Document;
            DocumentManager.CurrentRecorder.BeginAction("DIMRADIAL");
            var dimRadial = doc.CreateObject<DimRadial>();
            dimRadial.Start = this.point;
            dimRadial.End = this.center;

            LcText text = doc.CreateObject<LcText>();
            text.Start = this.point;
            text.TextStart = this.point;
            text.Heigh = 4;// this.raduis * 2 / 20 < 1 ? 1 : Math.Round(this.raduis * 2 / 20);
            text.Text = (this.raduis).ToString("0.00");
            text.Rotate = 180 / Math.PI * (this.point - this.center).Angle();
            text.Alignment = "左对齐";
            text.Widthfactor = 1;
            text.Tilt = 0;

            dimRadial.Dimtext = text;
            doc.ModelSpace.InsertElement(dimRadial);
            this.docRt.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }
       

        /// <summary>
        /// 选中的对象
        /// </summary>
        /// <param name="elements"></param>
        /// <returns></returns>
        private bool CreateSelects(LcElement elements)
        {

         
                if (elements is LcCircle|| elements is LcArc) {
                    return true;

                }
               
            return false;

        }


        /// <summary>
        /// 对一个坐标点按照一个中心进行旋转
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="p1">要旋转的点</param>
        /// <param name="angle">旋转角度，笛卡尔直角坐标</param>
        /// <returns></returns>
        private Vector2 PointRotate(Vector2 center, Vector2 p1, double angle)
        {
            Vector2 tmp = new Vector2();
            double angleHude = angle * Math.PI / 180;/*角度变成弧度*/
            double x1 = (p1.X - center.X) * Math.Cos(angleHude) + (p1.Y - center.Y) * Math.Sin(angleHude) + center.X;
            double y1 = -(p1.X - center.X) * Math.Sin(angleHude) + (p1.Y - center.Y) * Math.Cos(angleHude) + center.Y;
            tmp.X = (int)x1;
            tmp.Y = (int)y1;
            return tmp;
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
       
        

        public override void CreateElement(LcElement element, Matrix3 matrix)
        {
            DocumentManager.CurrentRecorder.BeginAction("Circle");
            var dim = element as DimRadial;
            this.vportRt.ActiveElementSet.AddDimRadial(matrix.MultiplyPoint(dim.Start), matrix.MultiplyPoint(dim.End),dim.Dimtext);
            DocumentManager.CurrentRecorder.EndAction();
        }
        public override void CreateElement(LcElement element,Vector2 basePoint, double scaleFactor)
        {
            var circle = element as LcCircle;
            Matrix3 matrix3 = Matrix3.GetScale(scaleFactor, basePoint);
            this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * scaleFactor);
        }
        public override void CreateElement(LcElement element, Vector2 basePoint, Vector2 scaleVector)
        {
            var circle = element as LcCircle;
            Matrix3 matrix3 = Matrix3.GetScale(scaleVector, basePoint);
            this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * Vector2.Distance(basePoint, scaleVector));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var dim = element as DimRadial;
            var mstart = matrix.MultiplyPoint(dim.Start);
            var mend = matrix.MultiplyPoint(dim.End);
            var mtext = dim.Dimtext;
            var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
            var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();
            //get Layer color 
            //bool isDragCopy = (matrix != Matrix3d.Zero);
            //var pen = this.GetDrawPen(dim, isDragCopy);
            Vector2 direction = new Vector2(dim.Start.X - dim.End.X, dim.Start.Y - dim.End.Y);
            double dis = Math.Abs(1000);
            Vector2 lidisptpos = dim.Start + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
            var mnewend = matrix.MultiplyPoint(lidisptpos);
            var newend = this.vportRt.ConvertWcsToScr(mnewend).ToSKPoint();

            var pen = this.GetDrawPen(element);
            if (pen == Constants.defaultPen)
            {
                //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                {

                    canvas.DrawLine(start, end, elePen);
                    canvas.DrawLine(start, newend, elePen);
                }
            }
            else
            {
                canvas.DrawLine(start, end, pen);
                canvas.DrawLine(start, newend, pen);
            }
            var path = DrawArrow(dim.Start, dim.End, 180);
            using (var pathPen = new SKPaint { Color = element.GetColorValue(), IsStroke = true })
            {
                pathPen.Style = SKPaintStyle.StrokeAndFill;
                pathPen.IsAntialias = true;
                pathPen.StrokeWidth = 2;
                //绘制路径
                canvas.DrawPath(path, pathPen);
            }
            var eleAction = (dim.Dimtext.RtAction as ElementAction);
            dim.Dimtext.Start = mstart;
            dim.Dimtext.Rotate = 180 / Math.PI * (mstart - mend).Angle();
            eleAction.SetViewport(this.vportRt).Draw(canvas, dim.Dimtext, new Matrix3());
        }

        /// <summary>
        /// 画箭头
        /// </summary>
        /// <param name="start">箭头指向点</param>
        /// <param name="end"></param>
        /// <param name="extraAngle">额外旋转角度</param>
        /// <returns></returns>
        private SKPath DrawArrow(Vector2 start, Vector2 end, double extraAngle = 0)
        {
            LcLine lcline = new LcLine();
            lcline.Start = start;
            lcline.End = end;
            var radian = lcline.Angle;

            var startve = new Vector2(lcline.Start.X, lcline.Start.Y);
            var arrowtwove = new Vector2(lcline.Start.X + 100, lcline.Start.Y + 30);
            var arrowendve = new Vector2(lcline.Start.X + 100, lcline.Start.Y - 30);
            var angle = Utils.RadianToDegree(radian) + extraAngle;
            arrowtwove = Vector2.Rotate(arrowtwove, startve, angle);
            arrowendve = Vector2.Rotate(arrowendve, startve, angle);

            var pointone = this.vportRt.ConvertWcsToScr(startve).ToSKPoint();
            var pointtwo = this.vportRt.ConvertWcsToScr(arrowtwove).ToSKPoint();
            var pointthree = this.vportRt.ConvertWcsToScr(arrowendve).ToSKPoint();

            var path = new SKPath();
            path.FillType = SKPathFillType.EvenOdd;
            //外圈 顺时针
            path.MoveTo((float)pointone.X, (float)pointone.Y);    //起点
            path.LineTo((float)pointtwo.X, (float)pointtwo.Y);
            path.LineTo((float)pointthree.X, (float)pointthree.Y);
            path.Close();
            return path;
        }

        public override void DrawAuxLines(SKCanvas canvas)
        {
            //if (this.point != null)
            //{
            //    var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            //    var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            //    DrawAuxLine(canvas, this.point, wcs_mp);
            //}
        }

        private void DrawAuxLine(SKCanvas canvas, Vector2 p0, Vector2 p1)
        {
            //var sk_pre = this.vportRt.ConvertWcsToScr(p0).ToSKPoint();
            //var sk_p = this.vportRt.ConvertWcsToScr(p1).ToSKPoint();
            ////辅助元素的颜色 
            //canvas.DrawLine(sk_pre, sk_p, Constants.auxElementPen);
            ////辅助曲线的颜色，包括辅助长度，辅助角度等
        }

        #region Grip
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var dimradial = element as DimRadial;
            var grips = new List<ControlGrip>();
            var gripStart = new ControlGrip {
                Element = dimradial,
                Name = "Start",
                Position = dimradial.Start
            };
            
            var gripEnd = new ControlGrip
            {
                Element = dimradial,
                Name = "End",
                Position = dimradial.End
            };
            grips.Add(gripStart);
            
            grips.Add(gripEnd);
            return grips.ToArray();
        }
        private string _gripName;
        private Vector2 _position;
        private DimRadial _dimradial;

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var dimradial = element as DimRadial;

            _dimradial = dimradial;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                //半径
                var radialradius = _dimradial.Length;
                //需要移动的向量方向
                Vector2 direction = new Vector2(0, 0);
                var radialstart = _dimradial.Start;
                var radialend = _dimradial.End;

                if (gripName == "Start")
                {
                    LcLine lcline = new LcLine(radialend, _position);
                    //需要移动的距离
                    double dis = Math.Abs(lcline.Length - radialradius);
                    if (lcline.Length > radialradius)
                    {
                        //向内延伸
                        direction = new Vector2(radialend.X - _position.X, radialend.Y - _position.Y);
                    }
                    else if (lcline.Length < radialradius)
                    {
                        //向外部延伸
                        direction = new Vector2(_position.X - radialend.X, _position.Y - radialend.Y);
                    }
                    Vector2 newpoint = new Vector2(_position.X, _position.Y);
                    if (direction.Length() != 0)
                    {
                        //新的移动后的点位
                        Vector2 lidisptpos = _position + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                        newpoint = lidisptpos;
                    }
                    radialstart = newpoint;
                    _dimradial.Set(start: radialstart);
                }
                else if (gripName == "End")
                {
                    direction = new Vector2(radialstart.X - _position.X, radialstart.Y - _position.Y);
                    radialend = new Vector2(_position.X, _position.Y);
                    Vector2 lidisptpos = _position + (new Vector2(direction.X * radialradius, direction.Y * radialradius)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                    radialstart = lidisptpos;
                    _dimradial.Set(end: position);
                    _dimradial.Set(start: radialstart);
                }
            }
        }


        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_dimradial == null) return;
            //半径
            var radialradius = _dimradial.Length;
            //需要移动的向量方向
            Vector2 direction = new Vector2(0, 0);
            var radialstart = _dimradial.Start;
            var radialend = _dimradial.End;
            var mtext = _dimradial.Dimtext;
            if (_gripName == "Start")
            {
                LcLine lcline = new LcLine(radialend, _position);
                //需要移动的距离
                double dis = Math.Abs(lcline.Length - radialradius);
                if (lcline.Length > radialradius)
                {
                    //向内延伸
                    direction = new Vector2(radialend.X - _position.X, radialend.Y - _position.Y);
                }
                else if (lcline.Length < radialradius)
                {
                    //向外部延伸
                    direction = new Vector2(_position.X - radialend.X, _position.Y - radialend.Y);
                }
                Vector2 newpoint = new Vector2(_position.X, _position.Y);
                if (direction.Length() != 0)
                {
                    //新的移动后的点位
                    Vector2 lidisptpos = _position + (new Vector2(direction.X * dis, direction.Y * dis)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                    newpoint = lidisptpos;
                }
                radialstart = newpoint;
            }
            if (_gripName == "End")
            {
                if (_position == radialend) return;
                direction = new Vector2(radialstart.X - _position.X, radialstart.Y - _position.Y);
                radialend = new Vector2(_position.X, _position.Y);
                Vector2 lidisptpos = _position + (new Vector2(direction.X * radialradius, direction.Y * radialradius)) / Math.Sqrt(Math.Abs((Math.Pow(direction.X, 2.0) + Math.Pow(direction.Y, 2.0))));
                radialstart = lidisptpos;
            }
            var start = this.vportRt.ConvertWcsToScr(radialstart);
            var end = this.vportRt.ConvertWcsToScr(radialend);

            Vector2 lengthen = new Vector2();
            if (_gripName == "Start")
                lengthen = new Vector2(radialstart.X - _dimradial.End.X, radialstart.Y - _dimradial.End.Y);
            if (_gripName == "End")
                lengthen = new Vector2(radialstart.X - radialend.X, radialstart.Y - radialend.Y);
            double newdis = Math.Abs(1000);
            Vector2 lengthenpoint = radialstart + (new Vector2(lengthen.X * newdis, lengthen.Y * newdis)) / Math.Sqrt(Math.Abs((Math.Pow(lengthen.X, 2.0) + Math.Pow(lengthen.Y, 2.0))));
            var newend = this.vportRt.ConvertWcsToScr(lengthenpoint).ToSKPoint();

            var pen = this.GetDrawPen(_dimradial);
            if (pen == Constants.defaultPen)
            {
                using (var elePen = new SKPaint { Color = new SKColor(_dimradial.GetColorValue()), IsStroke = true })
                {
                    canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), elePen);
                    canvas.DrawLine(start.ToSKPoint(), newend, elePen);
                }
            }
            else {
                canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), pen);
                canvas.DrawLine(start.ToSKPoint(), newend, pen);
            }
            var path = DrawArrow(radialstart, radialend, 180);
            using (var elePen = new SKPaint { Color = new SKColor(_dimradial.GetColorValue()), IsStroke = true })
            {
                elePen.Style = SKPaintStyle.StrokeAndFill;
                elePen.IsAntialias = true;
                elePen.StrokeWidth = 2;
                //绘制路径
                canvas.DrawPath(path, Constants.draggingPen);
            }
            this.vportRt.DrawText(radialstart, _dimradial.Dimtext.TextStart, _dimradial.Dimtext.Heigh, 180 / Math.PI * (radialstart - radialend).Angle(), _dimradial.Dimtext.Text, _dimradial.Dimtext.Tilt,
                    _dimradial.Dimtext.Typeface, _dimradial.Dimtext.Widthfactor, _dimradial.Dimtext.Alignment, new Matrix3(), canvas, Runtime.Constants.draggingPen);
        }

        #endregion

        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
            {
                
            };
        }
    }
}
